// gain access to the Prefences service.
var prefManager = Components.classes["@mozilla.org/preferences-service;1"].
                    getService(Components.interfaces.nsIPrefBranch);


// creates a prompt where the user can choose the folder where to save the logged pages
function setNewLogFolder(element){
	try {
		// create and initialize a file picker
		var nsIFilePicker = Components.interfaces.nsIFilePicker;
		var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
		fp.init(window, "Select a File", nsIFilePicker.modeGetFolder);
		var res = fp.show();
		// if the user selected a folder
		if (res == nsIFilePicker.returnOK){
	  		var theFolder = fp.file.path + '/'; // path normalization TODO check on other OS
			var loggingFolder = document.getElementById(element);
	  		loggingFolder.value = theFolder;
			// update the preference
			document.getElementById("peercafePane").userChangedValue(loggingFolder);
		}
	} catch(ex) {
		alert('exception in setNewLogFolder' + ex )
	}	
}

// this function resets the logging folder to the default one
function resetLogFolder(element){
	try {
		var theFolder = prefManager.getCharPref("extensions.peercafe.defaultLoggingFolder");
		var loggingFolder = document.getElementById(element);
  		loggingFolder.value = theFolder;
		document.getElementById("peercafePane").userChangedValue(loggingFolder);
	} catch(ex){
		alert('exception in resetLogFolder' + ex )
	}
}

// Reset to the default start peer
function resetStartPeer(element) {
  try {
    if (prefManager.prefHasUserValue("extensions.peercafe.startPeer")) {
      prefManager.clearUserPref("extensions.peercafe.startPeer");
    }
 } catch(ex) {
		alert('exception in resetStartPeer' + ex )
	}
}

/* this function is responsible for switching the loggin status of the plugin */
function switchLoggingState(){
	try {
		var currentState = prefManager.getBoolPref("extensions.peercafe.logging");
		// if it was true set it to false
		if (currentState){
			prefManager.setBoolPref("extensions.peercafe.logging", false);
		} else { // if it was false set it to true
			prefManager.setBoolPref("extensions.peercafe.logging", true);
		}
	} catch(ex){
		alert('exception in switchLoggingState' + ex )
	}
	
}

// this method will be called every time a window loads, so that the icon color will be
// taken from the preferences
function setIconColor(){
	try{
		var currentState = prefManager.getBoolPref("extensions.peercafe.logging");
		if (currentState){
			document.getElementById("peercafe_sbi").src = "chrome://peercafe/skin/browser/peercafeGreen18.gif";
		} else {
			document.getElementById("peercafe_sbi").src = "chrome://peercafe/skin/browser/peercafeRed18.gif";
		}
	}catch(ex){
		//alert('exception in getIconColor' + ex );
		setIconColorFromPref()
	}
}

/* This function sets and changes the color of the icon */
function setIconColorFromPref(){
	try{
		var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
		                   .getService(Components.interfaces.nsIWindowMediator);
		// get the handle to the window
		var browserWindow = wm.getMostRecentWindow("navigator:browser");
		var currentState = prefManager.getBoolPref("extensions.peercafe.logging");
		if (currentState){
			browserWindow.document.getElementById("peercafe_sbi").src = "chrome://peercafe/skin/browser/peercafeGreen18.gif";
		} else {
			browserWindow.document.getElementById("peercafe_sbi").src = "chrome://peercafe/skin/browser/peercafeRed18.gif";
		}
	}catch (ex){
		alert('exception in setIconColorFromPref' + ex );
	}	
}

// given a name policy, select just one box at a time
// 1 = random, 2 = urlhash, 3 = contenthash
function setNamingConvention(type){
	try {
		//alert('executing setNamingConvention, arg = ' + type);
		switch(type){
			// RANDOM
			case 1 : prefManager.setBoolPref("extensions.peercafe.random", true)
				prefManager.setBoolPref("extensions.peercafe.hashURL", false)
				prefManager.setBoolPref("extensions.peercafe.hashContent", false)
				break;
			// HASH URL
			case 2 : prefManager.setBoolPref("extensions.peercafe.random", false)
				prefManager.setBoolPref("extensions.peercafe.hashURL", true)
				prefManager.setBoolPref("extensions.peercafe.hashContent", false)
				break;
			// HASH CONTENT
			case 3 : prefManager.setBoolPref("extensions.peercafe.random", false)
				prefManager.setBoolPref("extensions.peercafe.hashURL", false)
				prefManager.setBoolPref("extensions.peercafe.hashContent", true)
				break;
			default : break;
		}
	} catch(ex){
		alert('exception in setNamingConvention ' + ex);
	}
}

/* This function will be called every time the pref panel will load.
It will populate the filter list, since it has to be parsed from the user preferences */
function populateFiltersList() {
	try{
		flipView("normal"); // show the informations, and NOT the edit panel
		var prefString = prefManager.getCharPref("extensions.peercafe.filters");

		if(prefString == "")
			return;

		var filters = prefString.split(".NEXT.");
		var filtersList = document.getElementById("filtersList");

		// create space and structure for the new elements
		for (var i=0; i < filters.length; i++) {
			var newItem = document.createElement("treeitem");
			var newRow = document.createElement("treerow");
			newItem.appendChild(newRow); // a row an element

	        var currentFilter = document.createElement("treecell");
			currentFilter.setAttribute("label", filters[i]);
			newRow.appendChild(currentFilter);

			filtersList.appendChild(newItem); // put the element in the structure
	      }
	} catch (ex) {
		alert('exception in populateFiltersList ' + ex); // can this alert blow up FF?
	}
}

// move up and down filter items inside the filer list
function move(dir) {
	try{
		var filtersTree = document.getElementById("filtersTree");
		var index = filtersTree.currentIndex;

		if(index != -1) {
			var filtersList = document.getElementById("filtersList");
			if(dir == "up" && index > 0) {
				var nextIndex = index - 1;
				var top = filtersList.childNodes[nextIndex];
				var bottom = filtersList.childNodes[index];
			} else if(dir == "down" && index < filtersList.childNodes.length - 1) {
				var nextIndex = index + 1;
				var top = filtersList.childNodes[index];
				var bottom = filtersList.childNodes[nextIndex];
			} else {
				return;
			}

			var oA = top.childNodes[0].childNodes[0].getAttribute("label");
			var iA = bottom.childNodes[0].childNodes[0].getAttribute("label");

			top.childNodes[0].childNodes[0].setAttribute("label", iA);
			bottom.childNodes[0].childNodes[0].setAttribute("label", oA);

			filtersList.currentIndex = nextIndex; // TODO why is it not working?

			filtersList.focus();

		    document.getElementById("peercafePane").userChangedValue(filtersTree);
		}
	} catch (ex){
		alert('exception in move ' + ex);
	}
}

// flip the hidden and visible boxes while in edit or normal mode (reguarding filters)
function flipView(mode) {
	try{
		var folderGroup = document.getElementById("loggingFolderGroupBox");
		var loggingGroup = document.getElementById("loggingStatusGroupBox");
		var namingGroup = document.getElementById("namingGroupBox");
		var filterListGroup = document.getElementById("filtersListGroupBox");
		var filterEditGroup = document.getElementById("filtersEditorGroupBox"); 
		var netGroup = document.getElementById("netSettingsGroupBox");

		if(mode == "edit") {
			folderGroup.setAttribute("hidden", "true");
			loggingGroup.setAttribute("hidden", "true");
			namingGroup.setAttribute("hidden", "true");
			filterListGroup.setAttribute("hidden", "true");
			netGroup.setAttribute("hidden", "true");
			filterEditGroup.setAttribute("hidden", "false");
		} else {
			folderGroup.setAttribute("hidden", "false");
			loggingGroup.setAttribute("hidden", "false");
			namingGroup.setAttribute("hidden", "false");
			filterListGroup.setAttribute("hidden", "false");
			netGroup.setAttribute("hidden", "false");
			filterEditGroup.setAttribute("hidden", "true");
		}
	}catch(ex){
		alert('exception in flipView ' + ex);
	}
}

// create a new filter, show the edit panel (that will be empty and ready to get a new filter)
function newFilter() {
	try{
		flipView("edit");
		populateEdit("","");
	}catch(ex){
		alert('exception in newFilter ' + ex);
	}
}

// given a filter and its index, populate the edit panel (empty args are feasible)
function populateEdit(filterStr, editIndexStr) {
	try{
		var locations = document.getElementById("filtersField");
		var editIndex = document.getElementById("editIndex");

		editIndex.value = "" + editIndexStr;
		locations.value = "" + filterStr;

		locations.focus();
	}catch(ex){
		alert('exception in populateEdit ' + ex);
	}
}

// using as reference the list structure, the content will be saved back into the user preferences
function saveFiltersList() {
	try{
		var filtersList = document.getElementById("filtersList").childNodes;
		var prefString = "";

		for (var i=0; i < filtersList.length; i++) {
			var columns = filtersList[i].childNodes[0].childNodes;
			var str = columns[0].getAttribute("label")
			if(prefString == "")
				prefString = str;
			else
				prefString += ".NEXT." + str;
	    }

		// return the new prefString to be stored by pref system
		return prefString;
	}catch(ex){
		alert('exception in saveFiltersList ' + ex);
		return "";
	}
}

// take the currently highlighted filter and populate the edit panel with that filter
function editFilter() {
	try{
		var filtersTree = document.getElementById("filtersTree");
		var selectedIndex = filtersTree.currentIndex;

		// Ignore the button if no filter selected
		if(selectedIndex == -1)
			return;

		var filtersList = document.getElementById("filtersList");
		var entry = filtersList.childNodes[selectedIndex].childNodes[0].childNodes;

		populateEdit(entry[0].getAttribute("label"), selectedIndex);

		flipView("edit");
	}catch(ex){
		alert('exception in editFilter ' + ex);
	}
}

// delete the currently highlighted filter
function deleteFilter() {
	try{
		var filtersTree = document.getElementById("filtersTree");
		var index = filtersTree.currentIndex;

		if(index != -1) {
			var filtersList = document.getElementById("filtersList");
			var toRemove = filtersList.childNodes.item(index);
			filtersList.removeChild(toRemove);
		    document.getElementById("peercafePane").userChangedValue(filtersTree);
		}
	}catch(ex){
		alert('exception in deleteFilter ' + ex);
	}
}

/* This is a syncro function, it is called every time there is a modification in the content
of the filter list, in order to save into the user preferences the latest changes */
function saveFilter() {
	try{
		var locations = document.getElementById("filtersField");
		var editIndex = document.getElementById("editIndex");	
		var filtersList = document.getElementById("filtersList");

		if(locations.value == "") {
			alert("You must enter a filter!");
			return;
		}

		var newRow = document.createElement("treerow");
		var newItem = document.createElement("treeitem");
		newItem.appendChild(newRow);

	 	var url = document.createElement("treecell");
		url.setAttribute("label", locations.value);
		newRow.appendChild(url);

		if(editIndex.value == "") {
			filtersList.appendChild(newItem);
		} else {
			var oldItem = filtersList.childNodes[parseInt(editIndex.value)];
			filtersList.replaceChild(newItem, oldItem);
		}

		var filtersTree = document.getElementById("filtersTree");
	    document.getElementById("peercafePane").userChangedValue(filtersTree);

		flipView("normal");
	}catch(ex){
		alert('exception in saveFilter ' + ex);
	}
}

// flip the view once again to the normal one
function cancelFilter() {
	try{
		flipView("normal");
	}catch(ex){
		alert('exception in cancelFilter ' + ex);
	}
	
}

// inject the url of the current page into the new filter box
function setToCurrentPage(element) {
	try{
		var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
					.getService(Components.interfaces.nsIWindowMediator);
		var win = wm.getMostRecentWindow("navigator:browser");
		if (win) {
			var homePageField = document.getElementById(element);
		      var newVal = "";

		      var tabbrowser = win.document.getElementById("content");
	      	var l = tabbrowser.browsers.length;
		      for (var i = 0; i < l; i++) {
	      	  if (i)
		          newVal += "|";
	      	  newVal += tabbrowser.getBrowserAtIndex(i).webNavigation.currentURI.spec;
		      }

	      	homePageField.value = newVal;
		      document.getElementById("peercafePane").userChangedValue(homePageField);
		}
	}catch(ex){
		alert('exception in setToCurrentPage ' + ex);
	}
}

// inject the url of one of the user bookmark (user choice) into the new filter box
function setToBookmark(element) {
	try{
		var rv = { url: null };
		document.documentElement.openSubDialog("chrome://browser/content/bookmarks/selectBookmark.xul",
		                                           "resizable", rv);  
		if (rv.url) {
			var homePageField = document.getElementById(element);
			homePageField.value = rv.url;
	      	document.getElementById("peercafePane").userChangedValue(homePageField);
		}
	}catch(ex){
		alert('exception in setToBookmark ' + ex);
	}
}

// returns true if the current url is blacklisted
function isBlackListed(url){
	try{
		var filtersString = prefManager.getCharPref("extensions.peercafe.filters"); // string!!
		// arrays of filters of different types
		var startFilters = new Array();
		var endFilters = new Array();
		var containFilters = new Array();
		var exactFilters = new Array();

		var filters = filtersString.split(".NEXT.");

		// for every filter, determine which type of filter it is
		for (var i = 0; i < filters.length; i++) {
			var currentFilter = filters[i];
			var firstStart = currentFilter.indexOf('*');
			var lastStar;
			// does it have an * ?
			if (firstStart != -1){
				// it has at least one *
				// now i will check if it is has 1 or 2 * (end/start or contains)
				lastStar = currentFilter.lastIndexOf('*');
				// check if there is just one *
				if (firstStart == lastStar){
					// start or end filter -> just one *
					if (firstStart == 0){ // * at the beginning?
						// end filter
						endFilters.push(currentFilter.substring(1, currentFilter.length))
					} else { // * at the end
						// start filter
						startFilters.push(currentFilter.substring(0, currentFilter.length - 1))
					}
				} else {
					// contains filter
					containFilters.push(currentFilter.substring(firstStart + 1, lastStar))
				}
			} else {
				// it is an EXACT MATCH
				exactFilters.push(currentFilter)
			}
		}

		/*
		alert('START \n' + startFilters.toString())
		alert('END \n' + endFilters.toString())
		alert('CONTAINS \n' + containFilters.toString())
		alert('EXACT \n' + exactFilters.toString())
		*/
		
		// return true if there is at least one filter for this url
		return _blackStart(url, startFilters) ||
			_blackEnd(url, endFilters) || 
			_blackContains(url, containFilters) ||
			_exactMatch(url, exactFilters);
		
		
	}catch(ex){
		alert('exception in isBlackListed ' + ex);
		return false
	}
}

// TODO refactor in a common method?

// does the url start with something forbidden?
function _blackStart(url, startFilters){
	try{
		// for every filer into the filters list
		for (var i = 0; i < startFilters.length; i++){
			// check if the url starts with that string
			if ((url.toString().search("^" + startFilters[i].toString())) != -1){
				//alert('BlackStart ' + url);
				return true;
			}
		}
		return false;
	}catch(ex){
		alert('exception in _blackStart ' + ex);
		return false;
	}
}

// does the url end with something forbidden?
function _blackEnd(url, endFilters){
	try{
		// for every filer into the filters list
		for (var i = 0; i < endFilters.length; i++){
			// check if the url ends with that string
			if ((url.toString().search(endFilters[i].toString() + "$")) != -1){
				//alert('BlackEnd ' + url);
				return true;
			}
		}
		return false;
	}catch(ex){
		alert('exception in _blackEnd ' + ex);
		return false;
	}
}

// does the url contain something forbidden?
function _blackContains(url, containFilters){
	try{
		// for every filer into the filters list
		for (var i = 0; i < containFilters.length; i++){
			// check if the url ends with that string
			if ((url.toString().search(containFilters[i].toString())) != -1){
				//alert('BlackContains ' + url);
				return true;
			}
		}
		return false;
	}catch(ex){
		alert('exception in _blackContains ' + ex);
		return false;
	}
}

// is the url something forbidden?
function _exactMatch(url, exactFilters){
	try{
		// for every filer into the filters list
		for (var i = 0; i < exactFilters.length; i++){
			// check if the url ends with that string
			if (url.toString() == exactFilters[i].toString()){
				//alert('BlackExactMath ' + url);
				return true;
			}
		}
		return false;
	}catch(ex){
		alert('exception in _exactMatch ' + ex);
		return false;
	}
}


function openContextMenu(){
	var logger = Components.classes['@peercafe.org/pcLogger;1']
					.createInstance(Components.interfaces.pcILogger);
	try{
		logger.pcLog('trying to open chrome://peercafe/content/info.xul' );
		window.open('chrome://peercafe/content/info.xul', 'PeerCafe Info', 'chrome');
	}catch(e){
		logger.pcLog('error while opening chrome://peercafe/content/info.xul -> ' + e);
	}
}


// Preference observer
var pcPrefObserver = {
  register: function(){
	//alert('registering the observer')
    var prefService = Components.classes["@mozilla.org/preferences-service;1"]
                                .getService(Components.interfaces.nsIPrefService);
	// get the branch I'm interested in..
    this._branch = prefService.getBranch("extensions.peercafe.");
    this._branch.QueryInterface(Components.interfaces.nsIPrefBranch2);
    this._branch.addObserver("", this, false);
  },

  unregister: function(){
    if(!this._branch) return;
    this._branch.removeObserver("", this);
  },

  // this function will automatically (without being explicitly called) notice changes in the prefs
  observe: function(aSubject, aTopic, aData){
    if(aTopic != "nsPref:changed") return;

    switch (aData) {
      case "logging":
        //alert('logging status changed')
		//logMessage('user changed logging status');
		
		try{
			setIconColor(); // since the status changed, change the icon color
		}catch(e){
			// do nothing
		}
		
        break;
	  case "logHistory":
		//alert('history changed')
		//refreshPcHistory(); // now done automatically by pref sync
		break;
    }
  }
}

// registering the observer, done at overlay time
pcPrefObserver.register();
